home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / presto / presto10.lha / src / dynix_timer.C < prev    next >
C/C++ Source or Header  |  1991-12-11  |  5KB  |  234 lines

  1.  
  2. /*
  3.  * Fast timers for Dynix.
  4.  *
  5.  *
  6.  *     Last modified:        6/16/89
  7.  *    by:            sandstro
  8.  *    reason:            added the equivalent of segvh()
  9.  *                to the mmap'd kernel code
  10.  *
  11.  *     Last modified:        1/2/88
  12.  *    by:            bnb
  13.  *    reason:            add print function
  14.  *
  15.  *    Last modified:        12/21/87
  16.  *    by:            bnb
  17.  *    reason:            add these comments
  18.  *
  19.  */
  20.  
  21. #include <sys/param.h>
  22. #include <sys/file.h>
  23. #include <signal.h>
  24. #include <stddef.h>
  25. #include <sys/mman.h>
  26. #include <osfcn.h>
  27. #include <nlist.h>
  28. #include <stream.h>
  29. #include "presto.h"
  30. #include <time.h>
  31.  
  32. extern void fatalerror();
  33. static void check_for_hole();
  34.  
  35. static shared_t struct nlist Namelist[]    =    {
  36.     { "_time" },
  37. #define X_TIME    0
  38.     { "" }
  39. };
  40.  
  41. #define VMUNIX            "/dynix"
  42. #define KMEM            "/dev/kmem"
  43.  
  44. shared_t Spinlock timer_lock;
  45. shared_t Spinlock *t_lock = &timer_lock;
  46. private_t int t_kmemfd = -1;
  47.  
  48. shared_t struct timeval *t_tv = 0;
  49. shared_t int t_tv_all_valid = 0;    // valid in all address spaces
  50. private_t int t_tv_im_valid = 0;    // valid in this address space
  51.  
  52. shared_t int t_refcnt = 0;
  53. shared_t unsigned long timer_offt;
  54. shared_t int timer_pgsz;
  55. shared_t caddr_t timer_base;
  56.  
  57. //
  58. // Always succeed, even if we can't map
  59. //
  60.  
  61. void
  62. Timer::init()
  63. {
  64.     t_lock->lock();
  65.     
  66.     t_refcnt++;
  67.  
  68.     if (t_tv)    {
  69.         // At least one address space has already
  70.         // initialized this timer.
  71.         t_starttime = getabsolutetime();
  72.         t_lock->unlock();
  73.         return;
  74.     }
  75.     
  76.     //
  77.     // ELSE, must map kernel time var into our address space
  78.     //
  79.  
  80.     if (nlist(VMUNIX, Namelist) < 0)    {
  81.         perror("Cant get namelist");
  82.         goto out;
  83.     }
  84.     
  85.     if (Namelist[X_TIME].n_type == 0)    {
  86.         cerr << "Help... namelist is insane\n";
  87.         goto out;
  88.     }
  89.     
  90.     t_kmemfd = open(KMEM, O_RDONLY, 0);
  91.     if (t_kmemfd < 0)    {
  92.         perror("open");
  93.         cerr << "Can't open kmem for time class\n";
  94.         goto out;
  95.     }
  96.     
  97.     if (lseek(t_kmemfd, (long)Namelist[X_TIME].n_value, 0) < 0)    {
  98.         perror("lseek");
  99.         cerr << "Can't lseek kmem for time class\n";
  100.         goto out;
  101.     }
  102.     
  103.     timer_pgsz = getpagesize();
  104.     timer_offt = Namelist[X_TIME].n_value & ~(timer_pgsz-1);
  105.     timer_base = grab_nonmalloc_hunk (timer_pgsz);
  106.     if (timer_base == (char *) -1) {
  107.         perror ("shbrk");
  108.         error ("Shbrk failed in Timer init");
  109.         goto out;
  110.     }
  111.     if (::mmap(timer_base, timer_pgsz, PROT_READ, MAP_SHARED,t_kmemfd, timer_offt) < 0) {
  112.         perror("mmap");
  113.         error("Can't map kmem first time");
  114.         goto out;
  115.     }
  116.     
  117.     t_tv =     (struct timeval*)(timer_base + Namelist[X_TIME].n_value - timer_offt);
  118.     t_tv_im_valid = 1;
  119.     t_starttime = getabsolutetime();
  120.     t_lock->unlock();
  121.     return;
  122.     
  123. out:        
  124.     if (t_tv == 0) {
  125.         t_tv = new timeval;    // static tv for ::gettimeofday
  126.         t_tv_all_valid = 1;
  127.     }
  128.     close(t_kmemfd);
  129.     t_kmemfd = -1;            // must use system call
  130.     t_lock->unlock();
  131.     return;
  132.  
  133. }
  134.  
  135. Timer::~Timer()
  136. {
  137.  
  138.     t_lock->lock();
  139.     
  140. #ifdef SANITY
  141.     if (t_refcnt <= 0)    {
  142.         cerr << "Warning:non-positive refcnt on time destructor\n";
  143.     }
  144. #endif
  145.     
  146.     t_refcnt--;
  147.     if (t_refcnt == 0)    {
  148.         if (t_kmemfd < 0) {
  149.             t_tv_all_valid = 0;
  150.             delete t_tv;
  151.         } else    {
  152.             close(t_kmemfd);
  153.             t_tv = 0;
  154.             t_kmemfd = -1;
  155.         }
  156.         t_lock->unlock();
  157.         delete t_lock;
  158.     } else
  159.         t_lock->unlock();
  160. }
  161.  
  162. double
  163. Timer::getabsolutetime()
  164. {
  165.     check_for_hole();
  166.     return (double)t_tv->tv_sec +
  167.         ((double)(t_tv->tv_usec) * 1.0e-6);
  168. }
  169.  
  170. char*
  171. Timer::getasciitime()
  172. {
  173.     check_for_hole();
  174.     return ctime((long*)&t_tv->tv_sec);
  175. }
  176.  
  177. /*
  178. struct timeval* 
  179. Timer::gettimeofday()
  180. {
  181.     check_for_hole();
  182.     if (t_kmemfd < 0) {            // couldn't map
  183.         ::gettimeofday(t_tv,0);
  184.     }
  185.     return t_tv;
  186. }
  187. */
  188. void
  189. Timer::print(ostream& s)
  190. {
  191.     check_for_hole();
  192.     s << form("(Timer)this= 0x%x,", this) << 
  193.          "t_lock= " << t_lock << "\n";
  194.     s << "t_tv= " << t_tv->tv_sec << ":" << t_tv->tv_usec << "\n";
  195.     s << "t_refcnt=" << t_refcnt << ", t_starttime = " << t_starttime;
  196. }
  197.  
  198. // The following routine, check_for_hole(), allows several address spaces
  199. // to check at the last minute whether they have memory mapped /dev/kmem,
  200. // and to map it if necessary.  Sequent offers something similar for
  201. // shbrk(), called segvh().  Segvh() is discussed in section 5.2 of
  202. // ``A Parallel Programming Process Model'' by Beck and Olien,
  203. // a paper distributed at the 1988 SURF in Newport Beach, CA.
  204. // Segvh() doesn't work here, because segvh() assumes that you
  205. // want to map the file descriptor _shm_fd to your address space.
  206.  
  207. static void check_for_hole()
  208. {
  209.     // This routine assumes that Timer::init() has been called.
  210.     if (t_tv_all_valid == 0) {
  211.     // At least one routine succeeded in mmapping the kernel,
  212.     // and no processes have yet tried and failed.
  213.     if (t_tv_im_valid == 0) {
  214.         // It wasn't us that succeeded in mmapping the kernel.
  215.         t_kmemfd = open (KMEM, O_RDONLY, 0);
  216.         if (t_kmemfd < 0) {
  217.         perror ("open");
  218.         error ("open kmem for Timer");
  219.         }
  220.         if (lseek (t_kmemfd, (long)Namelist[X_TIME].n_value, 0) < 0) {
  221.         perror ("lseek");
  222.         error ("lseek kmem for Timer");
  223.         }
  224.         if (::mmap(timer_base, timer_pgsz, PROT_READ, MAP_SHARED,
  225.         t_kmemfd, timer_offt) < 0) {
  226.         perror ("mmap");
  227.         error ("mmap kmem for Timer");
  228.         }
  229.     }
  230.     }
  231. }
  232.  
  233.  
  234.